/**********************************************************************************
 * Copyright (c) 2012 - 2012,  quick_tools, All right reserved
 * Title: com.adc.quicktools.net.smb  SMBUtil.java 
 * @author shen  shenqiao2012@163.com 
 *  2012-6-26 上午11:28:21 
 *********************************************************************************/

package com.adc.quicktools.net.smb;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.util.ArrayList;
//import java.util.HashMap;
import java.util.List;
//import java.util.Map;
import java.util.Properties;

import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;

import com.adc.quicktools.StringUtil;
import com.adc.quicktools.constants.ConstantDefine;
import com.adc.quicktools.file.FileControl;
import com.adc.quicktools.file.WildcardsFilter;

public class SMBUtil {

	
	/**
	 * 
	 * Description: 注册smb上传、下载时的主机的相关信息
	 * author:  shen
	 * @param host
	 * @param user
	 * @param password
	 * @param homeDir
	 * @return Properties
	 */
	public static Properties registSMBServerInfo(String host,String user,String password,String homeDir) {
		Properties properties=null;
		if (StringUtil.checkStringValue(host)&& StringUtil.checkStringValue(user)&&
				StringUtil.checkStringValue(homeDir)) {
			properties=new Properties();
			if (!StringUtil.checkStringValue(password)) {
				user="anonymous";
				password="";
			}
			properties.setProperty(ConstantDefine.SMB_Hostname_KEY, host);
			properties.setProperty(ConstantDefine.SMB_User_KEY, user);
			properties.setProperty(ConstantDefine.SMB_Pwd_KEY, password);
			properties.setProperty(ConstantDefine.SMB_Home_KEY, homeDir);
		}
		return properties;
	}
	
	/**
	 * 
	 * Description:   拼接smb上传路径的文件地址
	 * author:  shen 
	 * @param properties   包含机器的smb用户名、密码等信息的properties
	 * @param remotePath  远程路径，不包含ip
	 * @return String
	 */
	public static String makeSmbUrl(Properties properties,String remotePath){
		String fileSmbUrl="smb://"+properties.getProperty(ConstantDefine.SMB_User_KEY)+":"+
				properties.getProperty(ConstantDefine.SMB_Pwd_KEY)+"@"+
				properties.getProperty(ConstantDefine.SMB_Hostname_KEY);
		fileSmbUrl=fileSmbUrl.concat(remotePath);
		fileSmbUrl=fileSmbUrl.replace("\\", "/");
		System.out.println("[SMB]smb url:["+fileSmbUrl+"]");
		return fileSmbUrl;
	}

	/**
	 * 从局域网中共享文件中得到文件并保存在本地磁盘上,该方法只对文件名确定的smb文件、文件夹有效；
	 * 
	 * @param remoteUrl
	 *            共享电脑路径 如：smb//administrator:123456@172.16.10.136/smb/1221.zip
	 *            , smb为共享文件 注：如果一直出现连接不上，有提示报错，并且错误信息是 用户名活密码错误 则修改共享机器的文件夹选项
	 *            查看 去掉共享简单文件夹的对勾即可。
	 * @param localFilePath
	 *            本地文件路径 如：D:/1221.zip
	 * @param isFile true：表示localFilePath为文件；false：表示localFilePath为路径；
	 */
	public static List<String> downloadBySMB(String remoteUrl, String localFilePath,boolean isFile) {
		InputStream in = null;
		OutputStream out = null;
		List<String> result = null;
		if (StringUtil.checkStringValue(remoteUrl)&&StringUtil.checkStringValue(localFilePath)) {
			try {
				result = new ArrayList<String>();
				String fileName="";
				remoteUrl=remoteUrl.replace("\\", "/");
				String remoteParent=null;
				SmbFile smbFile = new SmbFile(remoteUrl);
				if (!remoteUrl.contains("*")&&!remoteUrl.contains("?")) {  //  对于不包含通配符时的文件夹、文件路径，可以进行判断；
					if (smbFile.isFile()) {
						remoteParent = StringUtil.getParentByString(remoteUrl);
						fileName = StringUtil.getNameByString(remoteUrl);
					} else if (smbFile.isDirectory()) {
						if (!remoteUrl.endsWith("/")) {
							remoteParent = remoteUrl.concat("/");
						}
						fileName = "*.*";
					} else {
						throw new IOException("The File or Directory [" + remoteUrl + "] is not exist!");
					}
				}else {
					fileName=StringUtil.getNameByString(remoteUrl);
					remoteParent=StringUtil.getParentByString(remoteUrl);
				}
				System.out.println("[SMB]FileName:["+fileName+"]");
				System.out.println("[SMB]File Parent Path:["+remoteParent+"]");
				SmbFile smb = new SmbFile(remoteParent);
				SmbFile[] files=smb.listFiles(fileName);
				String localParent=null;
				if (isFile) {
					localParent=StringUtil.getParentByString(localFilePath);
				}else {
					localParent=FileControl.checkDirEndWith(localFilePath).replace("\\", "/");
				}
				for (int i = 0; i < files.length; i++) {
					boolean b=false;
					in = new BufferedInputStream(new SmbFileInputStream(files[i]));
					String tempLocalPath="";
					if (files.length>1) {  //  文件列表不唯一时，需要对传入的本地路径进行判断；若为文件，则取其parentPath，若为路径，则直接使用；
						tempLocalPath=localParent.concat(files[i].getName());
					}else {
						if (isFile) {
							tempLocalPath=localFilePath;
						}else {
							tempLocalPath=localParent.concat(files[i].getName());
						}
					}
					out = new BufferedOutputStream(new FileOutputStream(tempLocalPath));
					if (in != null && out != null) {
						b = FileControl.writeOrReadAsStream(in, out);
					}
					System.out.println("[SMB]Count("+(i+1)+") \tFile:["+files[i].getName()+"] to local["+tempLocalPath+"],Result is ["+b+"]");
					if (b) {
						result.add(tempLocalPath);
					}
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.out.println("[SMB]Finally download fileList size is ["+result.size()+"]");
		}else {
			System.out.println("[SMB-ERROR]Parameters is null");
		}
		return result;
	}
	

	/**
	 * 把本地磁盘中的文件、文件夹上传到局域网共享文件下，该方法只对文件名确定的smb文件、文件夹有效；
	 * 
	 * @param remoteUrl
	 *            共享电脑路径 如：smb//administrator:123456@172.16.10.136/smb/1221.zip
	 * @param localFilePath
	 *            本地路径 如：D:/1221.zip
	 * @param isFile true：表示remoteUrl为文件；false：表示remoteUrl为路径； 
	 */
	public static List<String> uploadBySMB(String remoteUrl, String localFilePath,boolean isFile) {
		InputStream in = null;
		OutputStream out = null;
		List<String> result = null;
		if (StringUtil.checkStringValue(remoteUrl)&&StringUtil.checkStringValue(localFilePath)) {
			try {
				result = new ArrayList<String>();
				String fileName="";
				localFilePath=localFilePath.replace("\\", "/");
				String localParent=null;
				File localFile = new File(localFilePath);
				if (!localFilePath.contains("*")&&!localFilePath.contains("?")) {  //  对于不包含通配符时的文件夹、文件路径，可以进行判断；
					if (localFile.isFile()) {
						localParent = StringUtil.getParentByString(localFilePath);
						fileName = StringUtil.getNameByString(localFilePath);
					} else if (localFile.isDirectory()) {
						if (!localFilePath.endsWith("/")) {
							localParent = localFilePath.concat("/");
						}
						fileName = "";
					} else {
						throw new IOException("The File or Directory [" + localFilePath + "] is not exist!");
					}
				}else {
					localParent = StringUtil.getParentByString(localFilePath);
					fileName = StringUtil.getNameByString(localFilePath);
				}
				System.out.println("[SMB]FileName:["+fileName+"]");
				System.out.println("[SMB]File Parent Path:["+localParent+"]");
				File file = new File(localParent);
				File[] files=file.listFiles(new WildcardsFilter(fileName));
				String remoteParent=null;
				if (isFile) {
					remoteParent=StringUtil.getParentByString(remoteUrl);
				}else {
					remoteParent=FileControl.checkDirEndWith(remoteUrl).replace("\\", "/");
				}
				SmbFile remoteDir=new SmbFile(remoteParent);
				if (!remoteDir.exists()) {
					remoteDir.mkdirs();
				}
				for (int i = 0; i < files.length; i++) {
					boolean b=false;
					in = new FileInputStream(files[i].getPath());
					String tempRemotePath="";
					if (files.length>1) {  //  文件列表不唯一时，需要对传入的本地路径进行判断；若为文件，则取其parentPath，若为路径，则直接使用；
						tempRemotePath=remoteParent.concat(files[i].getName());
					}else {
						if (isFile) {
							tempRemotePath=remoteUrl;
						}else {
							tempRemotePath=remoteParent.concat(files[i].getName());
						}
					}
					out = new SmbFileOutputStream(tempRemotePath);
					if (in != null && out != null) {
						b = FileControl.writeOrReadAsStream(in, out);
					}
					System.out.println("[SMB]Count("+(i+1)+") \tFile:["+files[i].getName()+"] to Remote["+tempRemotePath+"],Result is ["+b+"]");
					if (b) {
						result.add(tempRemotePath);
					}
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[SMB]Finally download fileList size is ["+result.size()+"]");
		return result;

	}
	
	/**
	 * 
	 * Description: 将指定的smb具名文件，重命名为另外一个smb文件；(不同路径时，会移动文件；)
	 * author:  shen
	 * @param remoteFileUrl
	 * @param destRemoteFilePath
	 * @return boolean
	 */
	public static boolean renameAndMoveBySMB(String remoteFileUrl, String destRemoteFilePath) {
		boolean result=false;
		if (StringUtil.checkStringValue(remoteFileUrl)&&StringUtil.checkStringValue(destRemoteFilePath)) {
			try {
				SmbFile smbFile=new SmbFile(remoteFileUrl);
				if (smbFile.isFile()) {
					SmbFile destSmbFile=new SmbFile(destRemoteFilePath);
					String destParent=destSmbFile.getParent();
					SmbFile destParentSmb=new SmbFile(destParent);
					if (!destParentSmb.exists()) {
						destParentSmb.mkdirs();
					}
					smbFile.renameTo(destSmbFile);
					if (destSmbFile.exists()) {
						result=true;
					}
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[SMB]Rename ["+remoteFileUrl+"] to ["+destRemoteFilePath+"]! Result is ["+result+"]");
		return result;
	}
	
	/**
	 * 
	 * Description: 将指定的smb文件，复制为另外一个smb文件；或将指定的文件夹复制到另外一个文件夹；
	 * author:  shen
	 * @param remoteFileUrl
	 * @param destRemoteFilePath
	 * @return boolean
	 */
	public static boolean copyToBySMB(String remoteFileUrl, String destRemoteFilePath) {
		boolean result=false;
		if (StringUtil.checkStringValue(remoteFileUrl)&&StringUtil.checkStringValue(destRemoteFilePath)) {
			try {
				SmbFile smbFile=new SmbFile(remoteFileUrl);
				SmbFile destSmbFile=new SmbFile(destRemoteFilePath);
				String destParent=null;
				if (smbFile.isFile()) {
					destParent = destSmbFile.getParent();
				}else if (smbFile.isDirectory()){
					destParent=destRemoteFilePath;
				}
				SmbFile destParentSmb=new SmbFile(destParent);
				if (!destParentSmb.exists()) { // 保证目的路径的文件夹全部创建；
					destParentSmb.mkdirs();
				}
				if (!destParent.endsWith("\\")&&!destParent.endsWith("/")) {
					destParent=destParent.replace("\\", "/").concat("/");
				}
				if (smbFile.isFile()) {
					smbFile.copyTo(destSmbFile);
					if (destSmbFile.exists()) {
						result=true;
					}
				}else if (smbFile.isDirectory()) {
					result=recursivelyCopyFoldersBySMB(smbFile.getPath(), destParent);
				}else {
					throw new IOException("Can not copy File or Directory ["+remoteFileUrl+"] to ["+destRemoteFilePath+"]");
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[SMB]Rename ["+remoteFileUrl+"] to ["+destRemoteFilePath+"]! Result is ["+result+"]");
		return result;
	}
	
	/**
	 * 
	 * Description: 递归复制共享目录上的文件夹
	 * author:  shen
	 * @param folderPath
	 * @return boolean
	 */
	private static boolean recursivelyCopyFoldersBySMB(String folderPath,String destFolderPath) {
		boolean result=false;
		if (StringUtil.checkStringValue(folderPath)&&StringUtil.checkStringValue(destFolderPath)) {
			try {
				folderPath=folderPath.replace("\\", "//");
				SmbFile folder = new SmbFile(folderPath);
				SmbFile destFolder=new SmbFile(destFolderPath);
				if (!destFolderPath.endsWith("/")&&!destFolderPath.endsWith("\\")) {
					destFolderPath=destFolderPath.concat("/");
				}
				if (!destFolder.exists()) {
					destFolder.mkdirs();
				}
				if (folder.isDirectory()) {
					SmbFile[] files = folder.listFiles();
					for (SmbFile smbFile : files) {
						SmbFile tempFile=new SmbFile(destFolderPath.concat(smbFile.getName()));
						if (smbFile.isFile()) {
							smbFile.copyTo(tempFile);
						} else if (smbFile.isDirectory()) {
							recursivelyCopyFoldersBySMB(smbFile.getPath(),tempFile.getPath());
						} else {
							System.out.println("[SMB]The folder[" + smbFile.getParent() + "] cannot be copy!");
						}
					}
					if (folder.list().length==destFolder.list().length) {
						result = true;
					}
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[SMB]Copy Folder["+folderPath+"] to ["+destFolderPath+"]: result is ["+result+"]");
		return result;
	}
	
	/**
	 * 
	 * Description: 删除共享目录上的文件或文件夹；
	 * author:  shen
	 * @param remoteUrl 远程文件、文件夹的路径
	 * @return boolean
	 */
	public static boolean deleteBySMB(String remoteUrl) {
		boolean result =false;
		if (StringUtil.checkStringValue(remoteUrl)) {
			try {
				SmbFile smbFile=new SmbFile(remoteUrl);
				String parent=smbFile.getParent();
				String nameString=smbFile.getName();
				SmbFile[] smbFiles=new SmbFile(parent).listFiles(nameString);
				for (int i = 0; i < smbFiles.length; i++) {
					if (smbFiles[i].isFile()) {
						smbFiles[i].delete();
					} else if (smbFiles[i].isDirectory()) {
						System.out.println("["+smbFiles[i].getPath()+"] is Directory,delete result is ["+recursivelyDeleteFoldersBySMB(smbFiles[i].getPath())+"]");
					}
				}
				if (!smbFile.exists()) {
					result=true;
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[SMB]Finally, Delete ["+remoteUrl+"] result is ["+result+"]");
		return result;
	}
	
	/**
	 * 
	 * Description: 递归删除共享目录上的文件夹
	 * author:  shen
	 * @param folderPath
	 * @return boolean
	 */
	private static boolean recursivelyDeleteFoldersBySMB(String folderPath) {
		boolean result=false;
		if (StringUtil.checkStringValue(folderPath)) {
			try {
				SmbFile folder = new SmbFile(folderPath);
				if (folder.isDirectory()) {
					SmbFile[] files = folder.listFiles();
					for (SmbFile smbFile : files) {
						if (smbFile.isFile()) {
							smbFile.delete();
						} else if (smbFile.isDirectory()) {
							recursivelyDeleteFoldersBySMB(smbFile.getPath());
						} else {
							System.out.println("[SMB]The folder[" + smbFile.getParent() + "] cannot be deleted!");
						}
					}
					folder.delete();
					if (!folder.exists()) {
						result = true;
					}
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[SMB]Delete Folder["+folderPath+"]: result is ["+result+"]");
		return result;
	}
	
	/**
	 * 
	 * Description: 列出指定smb目录下，匹配的所有文件的文件名
	 * author:  shen
	 * @param remoteParentPath
	 * @param wildcardFileName
	 * @return List<String>
	 */
	public static List<String> getNameListBySMB(String remoteParentPath,String wildcardFileName) {
		List<String> resultList=null;
		if (StringUtil.checkStringValue(remoteParentPath)) {
			SmbFile[] smbFiles=null;
			try {
				SmbFile smbFile=new SmbFile(remoteParentPath);
				if (!StringUtil.checkStringValue(wildcardFileName)) {
					smbFiles=smbFile.listFiles();
				}else {
					smbFiles=smbFile.listFiles(wildcardFileName);
				}
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (SmbException e) {
				e.printStackTrace();
			}
			if (smbFiles!=null && smbFiles.length>0) {
				resultList=new ArrayList<String>();
				for (SmbFile sFile : smbFiles) {
					resultList.add(sFile.getName());
				}
			}
		}
		System.out.println("[SMB]List All file names with format[wildcardFileName:"+wildcardFileName+"] in dir [remoteParentPath:"+remoteParentPath+"]");
		return resultList;
	}
	
//	/**
//	 * 
//	 * Description:  根据通配符，匹配samba目录下的文件，并将满足匹配条件的文件下载下来,返回本地临时文件的全路径；
//	 * author:  shen
//	 * @param remoteDirUrl
//	 * @param matchString
//	 * @param localDir
//	 * @return List<String>
//	 */
//	public static List<String> downloadBySMBWithWildcards(String remoteDirUrl,String matchString,String localFilePath) {
//		InputStream in = null;
//		OutputStream out = null;
//		List<String> result = new ArrayList<String>();
//		String localDir=new File(localFilePath).getParent().replace("\\", "/");
//		String fileName=new File(localFilePath).getName();
//		String fileNameWithOutSuffix=fileName.substring(0, fileName.lastIndexOf("."));
//		List<MultiFileMatchDto> waitforDownloadList=new ArrayList<MultiFileMatchDto>();
//		try {
//			SmbFile smbFile = new SmbFile(remoteDirUrl);
//			SmbFile[] fileArray=smbFile.listFiles(matchString); 
//			List<MultiFileMatchDto> downloadFileNames=new ArrayList<MultiFileMatchDto>();
//			for (int i = 0; i < fileArray.length; i++) {
//				if (WildcardUtil.chkFileNameIsMatched(matchString)) {
//					downloadFileNames.add(new MultiFileMatchDto(fileArray[i], localDir));
//				}
//			}
//			waitforDownloadList=getFomartLocalNameList(downloadFileNames, fileNameWithOutSuffix);
//			for (int j = 0; j < waitforDownloadList.size(); j++) {  //  need to download filelist
//				boolean b=false;
//				in = new BufferedInputStream(new SmbFileInputStream(waitforDownloadList.get(j).getSmbFile()));
//				String localTempString=FileControl.checkDirEndWith(
//						waitforDownloadList.get(j).getLocalDir()).replace("\\", "/")
//						+waitforDownloadList.get(j).getLocalFileName();
//				System.out.println("Matching File:"+localTempString);
//				out = new BufferedOutputStream(new FileOutputStream(localTempString));
//				b = FileControl.writeOrReadAsStream(in, out);
//				if (b) {
//					result.add(localTempString);
//				}
//			}
//			
//		} catch (MalformedURLException e) {
//			e.printStackTrace();
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		} catch (SmbException e) {
//			e.printStackTrace();
//		} catch (UnknownHostException e) {
//			e.printStackTrace();
//		}finally{
//			try {
//				in.close();
//				out.close();
//			} catch (IOException e) {
//				e.printStackTrace();
//			}
//		}
//		System.out.println("The Size of Matched File List is:"+result.size());
//		return result;
//	}
//
//	
//	
//	/**
//	 * 
//	 * Description: 将列表中的每个文件名按照列表中最短文件名除后缀外的字符长度替换；
//	 * 如AAA0001.txt、AAA0001_1.txt、AAA0001_2.txt是根据通配符AAA000*.txt匹配出的文件列表，替换文件名是A_A_B_2.txt；
//	 * 通过该方法可以获得A_A_B_2.txt、A_A_B_2_1.txt、A_A_B_2_2.txt;该函数的应用场景较小；被调用前已经进行多次匹配的确认；
//	 * author:  shen
//	 * @param tempNameList
//	 * @param matchName
//	 * @return List<MultiFileMatchDto>
//	 */
//	private static List<MultiFileMatchDto> getFomartLocalNameList(List<MultiFileMatchDto> tempList,String matchName) {
//		Map<String, MultiFileMatchDto> map=new HashMap<String, MultiFileMatchDto>();
//		List<String> nameList=new ArrayList<String>();
//		List<MultiFileMatchDto> resultList=new ArrayList<MultiFileMatchDto>();
//		for (MultiFileMatchDto smbFileDto : tempList) {
//			String locName=smbFileDto.getSmbFile().getName();
//			nameList.add(locName);
//			map.put(locName, smbFileDto);
//		}
//		
//		nameList=StringUtil.sortByLength(nameList);
//		int minFileLengthWithoutSuffix=nameList.get(0).substring(0, nameList.get(0).lastIndexOf(".")).length();
//		MultiFileMatchDto matchDto=new MultiFileMatchDto();
//		for (int i = 0; i < nameList.size(); i++) {  //  rename local temp file
//			String temp=nameList.get(i);
//			temp=StringUtil.replaceByIndex(temp, matchName, 0, minFileLengthWithoutSuffix);
//			matchDto=map.get(nameList.get(i));
//			matchDto.setLocalFileName(temp);
//			resultList.add(matchDto);
//		}
//		return resultList;
//	}

}
